/*******************************************************************************
 * Copyright (c) 2000, 2005 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package com.architexa.org.eclipse.draw2d;

import com.architexa.org.eclipse.draw2d.geometry.Dimension;
import com.architexa.org.eclipse.draw2d.geometry.Insets;
import com.architexa.org.eclipse.draw2d.geometry.Rectangle;
import com.architexa.org.eclipse.draw2d.geometry.Transposer;

/**
 * Lays out the Figures that make up a ScrollBar.
 */
public class ScrollBarLayout
	extends AbstractLayout
{

/** Used as a constraint for the up arrow figure. */
public static final String UP_ARROW   = "up arrow";   //$NON-NLS-1$
/** Used as a constraint for the down arrow figure. */
public static final String DOWN_ARROW = "down arrow"; //$NON-NLS-1$
/** Used as a constraint for the thumb figure. */
public static final String THUMB      = "thumb";      //$NON-NLS-1$
/** Used as a constraint for the page up figure. */
public static final String PAGE_UP    = "page_up";    //$NON-NLS-1$
/** Used as a constraint for the page down figure. */
public static final String PAGE_DOWN  = "page_down";  //$NON-NLS-1$

IFigure up, down, thumb, pageUp, pageDown;

/**
 * Transposes values if the ScrollBar is horizontally oriented. When used properly, the 
 * layout manager just needs to code for one case: vertical orientation.
 */
protected final Transposer transposer;

/**
 * Constructs a ScrollBarLayout. If the given Transposer is enabled, the Scrollbar will 
 * be horizontally oriented. Otherwise, the ScrollBar will be vertically oriented.
 * 
 * @param t the Transposer
 * @since 2.0
 */
public ScrollBarLayout(Transposer t) {
	transposer = t;
}

/**
 * @see AbstractLayout#setConstraint(IFigure, Object)
 */
public void setConstraint(IFigure figure, Object constraint) {
	if (constraint.equals(UP_ARROW))
		up = figure;
	else if (constraint.equals(DOWN_ARROW))
		down = figure;
	else if (constraint.equals(THUMB))
		thumb = figure;
	else if (constraint.equals(PAGE_UP))
		pageUp = figure;
	else if (constraint.equals(PAGE_DOWN))
		pageDown = figure;
}

/**
 * @see AbstractLayout#calculatePreferredSize(IFigure, int, int)
 */
protected Dimension calculatePreferredSize(IFigure parent, int w, int h) {
	Insets insets = transposer.t(parent.getInsets());
	Dimension d = new Dimension(16, 16 * 4);
	d.expand(insets.getWidth(), insets.getHeight());
	return transposer.t(d);
}

/**
 * @see LayoutManager#layout(IFigure)
 */
public void layout(IFigure parent) {
	ScrollBar scrollBar = (ScrollBar) parent;

	Rectangle trackBounds = layoutButtons(scrollBar);

	int extent = scrollBar.getExtent();
	int max = scrollBar.getMaximum();
	int min = scrollBar.getMinimum();
	int totalRange =  max - min;
	int valueRange = totalRange - extent;
	if ((valueRange < 1) || (!scrollBar.isEnabled())) {
		Rectangle boundsUpper = new Rectangle(trackBounds),
		          boundsLower = new Rectangle(trackBounds);
		boundsUpper.height /= 2;
		boundsLower.y += boundsUpper.height;
		boundsLower.height = trackBounds.height - boundsUpper.height;
		if (pageUp != null)
			pageUp.setBounds(transposer.t(boundsUpper));
		if (pageDown != null)
			pageDown.setBounds(transposer.t(boundsLower));
		return;
	}

	if (totalRange == 0)
		return;
	int thumbHeight = Math.max(thumb == null ? 0 : thumb.getMinimumSize().height,
								trackBounds.height * extent / totalRange);

	if (thumb != null)
		thumb.setVisible(trackBounds.height > thumbHeight);

	int thumbY = trackBounds.y + (trackBounds.height - thumbHeight) 
					* (scrollBar.getValue() - min) / valueRange;

	Rectangle thumbBounds =  new Rectangle(
		trackBounds.x,
		thumbY,
		trackBounds.width,
		thumbHeight);

	if (thumb != null)
		thumb.setBounds(transposer.t(thumbBounds));

	if (pageUp != null)
		pageUp.setBounds(transposer.t(new Rectangle(
			trackBounds.x,
			trackBounds.y,
			trackBounds.width,
			thumbBounds.y - trackBounds.y)));

	if (pageDown != null)
		pageDown.setBounds(transposer.t(new Rectangle(
			trackBounds.x ,
			thumbBounds.y + thumbHeight,
			trackBounds.width,
			trackBounds.bottom() - thumbBounds.bottom())));
}

/**
 * Places the buttons and returns the Rectangle into which the track should be placed.
 * The track consists of the pageup, pagedown, and thumb figures. The Rectangle returned 
 * should be transposed correctly, that is, it should be vertically oriented.  Users of 
 * the rectangle will re-transpose it for horizontal use.
 * 
 * @param scrollBar the scrollbar whose buttons are being layed out
 * @return the Rectangle into which the track should be placed 
 * @since 2.0
 */
protected Rectangle layoutButtons(ScrollBar scrollBar) {
	Rectangle bounds = transposer.t(scrollBar.getClientArea());
	Dimension buttonSize = new Dimension(
		bounds.width,
		Math.min(bounds.width, bounds.height / 2));

	if (up != null)
		up.setBounds(transposer.t(
			new Rectangle(bounds.getTopLeft(), buttonSize)));
	if (down != null) {
		Rectangle r = new Rectangle (
			bounds.x, bounds.bottom() - buttonSize.height,
			buttonSize.width, buttonSize.height);
		down.setBounds(transposer.t(r));
	}

	Rectangle trackBounds = bounds.getCropped(
		new Insets(
			(up   == null) ? 0 : buttonSize.height, 0,
			(down == null) ? 0 : buttonSize.height, 0));

	return trackBounds;
}

/**
 * @see LayoutManager#remove(IFigure)
 */
public void remove(IFigure child) {
	if (child == up) {
		up = null;
	} else if (child == down) {
		down = null;
	} else if (child == thumb) {
		thumb = null;
	} else if (child == pageUp) {
		pageUp = null;
	} else if (child == pageDown) {
		pageDown = null;
	}
}
}
